package com.baor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baor.dao.*;
import com.baor.domain.*;
import com.baor.domain.middle.Nouse;
import com.baor.domain.middle.RewardRuleMiddle;
import com.baor.enums.FuncEnum;
import com.baor.service.RewardService;
import com.baor.utils.AjaxResult;
import com.baor.utils.DateUtil;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ScheduledFuture;
import java.util.stream.Collectors;

import static com.baor.utils.DateUtil.now;

@Service
public class RewardServiceImpl implements RewardService {

    @Autowired
    private RewardDao rewardDao;
    @Autowired
    private RuleDao ruleDao;
    @Autowired
    private RewardRuleDao rewardRuleDao;
    @Autowired
    private DistributorDao distributorDao;
    @Autowired
    private CycleDao cycleDao;
    @Autowired
    private VipDao vipDao;
    @Autowired
    private MoneyDao moneyDao;
    @Override
    @Transactional
    public AjaxResult<?> addConf(Map<String, Object> params) {
        List<CycleVo> cycleVos = cycleDao.selectList(new LambdaQueryWrapper<CycleVo>().orderByDesc(CycleVo::getCycleEndTime));
        if(cycleVos.size() > 0){
            CycleVo cycleVoss = cycleVos.get(0);
            String now = DateUtil.now2();
            String end = cycleVoss.getCycleEndTime();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try{
                Date start = sdf.parse(now);
                Date end1 = sdf.parse(end);
                if(start.before(end1)){
                    return AjaxResult.error("当前时间未超过最晚周期结束时间，请选择其他时间");
                }
            }catch (Exception e){
                return AjaxResult.error("时间格式错误");
            }
        }
        //插入reward表，插入reward_rule中间表，插入rule表
        RewardVo vo = new RewardVo();
        vo.setCreateTime(DateUtil.now());
        vo.setConfStatus(params.get("confStatus").toString());
        vo.setConfCycle(params.get("cycle").toString());
        vo.setConfMethod(params.get("confMethod").toString());
        vo.setSiteId(params.get("siteId").toString());
        BigDecimal confBasic = new BigDecimal(String.valueOf(params.get("confBasic")));
        vo.setConfBasic(confBasic);
        if(Integer.valueOf(params.get("cycle").toString()) == 0){
            vo.setConfTime(DateUtil.getPerFirstDayOfMonth());
        }else if(Integer.valueOf(params.get("cycle").toString()) == 1){
            vo.setConfTime(DateUtil.getPerFirstDayOfNextQuarter());
        }else{
            vo.setConfTime((String) params.get("confTime"));
        }
        rewardDao.insert(vo);
        List<Map<String, Object>> arr = (List<Map<String, Object>>) params.get("rewardArr");
        RewardRuleMiddle middle = new RewardRuleMiddle();
        middle.setSiteId(params.get("siteId").toString());
        middle.setRewardId(vo.getRewardConfId());
        RuleVo ruleVo = new RuleVo();
        ruleVo.setSiteId(params.get("siteId").toString());
        for (Map<String, Object> rule : arr) {
            ruleVo.setRuleId(null);
            BigDecimal ruleMoney = new BigDecimal(String.valueOf(rule.get("ruleMoney")));
            ruleVo.setRuleMoney(ruleMoney);
            ruleVo.setRuleRange((Integer) rule.get("ruleRange"));
            ruleDao.insert(ruleVo);
            middle.setRuleId(ruleVo.getRuleId());
            rewardRuleDao.insert(middle);
        }
        //插入周期表
        CycleVo cycleVo = new CycleVo();
        cycleVo.setRewardConfId(String.valueOf(vo.getRewardConfId()));
        cycleVo.setSiteId(params.get("siteId").toString());
        cycleVo.setCycleStartTime(vo.getCreateTime());
        cycleVo.setCycleEndTime(vo.getConfTime());
        cycleVo.setRewardType(params.get("cycle").toString());
        cycleVo.setSummaryTime(vo.getConfTime());
        if(Integer.valueOf(params.get("confMethod").toString()) == 1){
            cycleVo.setGrantTime(vo.getConfTime());
        }
        int row = cycleDao.insert(cycleVo);
        if(row > 0){
            return AjaxResult.success();
        }else {
            return AjaxResult.error();
        }
    }
    @Override
    public AjaxResult<?> cycleList(Map<String, Object> params) {
        MPJLambdaWrapper<CycleVo> mpj = new MPJLambdaWrapper<>();
        mpj.selectAll(CycleVo.class)
               .eq(CycleVo::getSiteId, params.get("siteId"))
                .selectFunc(FuncEnum.CASE_CYCLE, CycleVo::getRewardType)
                .selectFunc(FuncEnum.IF_SUMMARY, CycleVo::getSummaryStatus)
                .selectFunc(FuncEnum.IF_GRANT, CycleVo::getGrantStatus)
                .selectAs(RewardVo::getConfMethod, CycleVo::getGrantMethod)
                .leftJoin(RewardVo.class, RewardVo::getRewardConfId, CycleVo::getRewardConfId);
        if(params.get("summaryStartTime") != null && !"".equals(params.get("summaryStartTime"))){
            mpj.gt(CycleVo::getSummaryTime, params.get("summaryStartTime"))
                    .lt(CycleVo::getSummaryTime, params.get("summaryEndTime"));
        }
        if(params.get("grantStartTime") != null && !"".equals(params.get("grantStartTime"))){
            mpj.gt(CycleVo::getSummaryTime, params.get("grantStartTime"))
                    .lt(CycleVo::getSummaryTime, params.get("grantEndTime"));
        }
        if(params.get("summaryStatus") != null && !"".equals(params.get("summaryStatus"))){
            mpj.eq(CycleVo::getSummaryStatus, params.get("summaryStatus"));
        }
        if(params.get("grantStatus") != null && !"".equals(params.get("grantStatus"))){
            mpj.eq(CycleVo::getGrantStatus, params.get("grantStatus"));
        }
        Page<CycleVo> page = getPage(params);
        List<CycleVo> list = cycleDao.selectPage(page, mpj).getRecords();
        for(CycleVo cycleVo : list){
            //计算所有分销商的销售总金额
            cycleVo.setTotalMoney(rewardDao.sumAmount(cycleVo));
            //查出奖励指标
            RewardVo rewardVo = rewardDao.selectById(cycleVo.getRewardConfId());
            if(Integer.parseInt(rewardVo.getConfStatus()) == 0){
                cycleVo.setRewardMoney(BigDecimal.ZERO);
                continue;
            }
            BigDecimal confBasic = rewardVo.getConfBasic();
            //查出该周期内所有奖励规则
            List<RuleVo> list2 = getRule(Integer.parseInt(cycleVo.getRewardConfId()));
            //计算分销商们的销售金额
            List<Nouse> list3 = rewardDao.sumReward(cycleVo);
            //过滤掉没有达到销售指标的分销商
            List<Nouse> list4 = list3.stream().filter(item -> item.getGoodsValue().compareTo(confBasic) >= 0).collect(Collectors.toList());
            int count = list4.size();
            BigDecimal rewardMoney = new BigDecimal(0);
            for(RuleVo ruleVo : list2){
               if(count > ruleVo.getRuleRange()) {
                   rewardMoney = rewardMoney.add(ruleVo.getRuleMoney().multiply(new BigDecimal(ruleVo.getRuleRange())));
                    count -= ruleVo.getRuleRange();
               }else{
                   rewardMoney = rewardMoney.add(ruleVo.getRuleMoney().multiply(new BigDecimal(count)));
                   break;
               }
            }
            cycleVo.setRewardMoney(rewardMoney);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("list", list);
        map.put("pageCount", page.getPages());
        return AjaxResult.success(map);
    }

    @Override
    public AjaxResult<?> checkDetails(Map<String, Object> param) {
        List<CycleVo> cycleList = new ArrayList<>();
        //查出周期信息
        MPJLambdaWrapper<CycleVo> mpj = new MPJLambdaWrapper<>();
        mpj.selectAll(CycleVo.class)
                .eq(CycleVo::getCycleId, param.get("cycleId"))
                .selectFunc(FuncEnum.CASE_CYCLE, CycleVo::getRewardType)
                .selectFunc(FuncEnum.IF_SUMMARY, CycleVo::getSummaryStatus)
                .selectFunc(FuncEnum.IF_GRANT, CycleVo::getGrantStatus);
        CycleVo cycleVo = cycleDao.selectOne(mpj);
        if(cycleVo == null){
            return AjaxResult.error("周期不存在");
        }
        //查出奖励指标
        RewardVo rewardVo = rewardDao.selectById(cycleVo.getRewardConfId());
        BigDecimal confBasic = rewardVo.getConfBasic();
        //查出该周期的所有奖励规则
        List<RuleVo> list2 = getRule(Integer.parseInt(cycleVo.getRewardConfId()));
        //查出所有分销商用户id
        List<Integer> distributorIds = distributorDao.selectList(null)
                .stream()
                .map(DistributorVo::getUserId)
                .map(Integer::parseInt).collect(Collectors.toList());
        //查出分销商的销售金额
        List<Nouse> list = rewardDao.sumReward(cycleVo);
        List<Integer> nouseIds = list.stream().map(Nouse::getUserId).collect(Collectors.toList());
        //判断该周期是否开启奖励配置
        if(Integer.parseInt(rewardVo.getConfStatus()) == 0){
            cycleVo.setRewardMoney(BigDecimal.ZERO);
            for(Integer distributorId : distributorIds){
                for(Nouse nouse : list){
                    if(nouse.getUserId() == distributorId){
                        CycleVo vo = copy(cycleVo);
                        vo.setTotalMoney(nouse.getGoodsValue());
                        vo.setUserName(nouse.getUserName());
                        cycleList.add(vo);
                    }
                }
            }
            distributorIds.removeAll(nouseIds);
            for(Integer distributorId : distributorIds) {
                String userName = vipDao.selectById(distributorId).getUserName();
                CycleVo vo = copy(cycleVo);
                vo.setUserName(userName);
                vo.setRewardMoney(BigDecimal.ZERO);
                vo.setTotalMoney(BigDecimal.ZERO);
                cycleList.add(vo);
            }
            Map<String, Object> map = getMap(param, cycleList);
            return AjaxResult.success(map);
        }
        //过滤掉没有达到销售指标的分销商
        List<Nouse> list1 = list.stream().filter(item -> item.getGoodsValue().compareTo(confBasic) >= 0).collect(Collectors.toList());
        int count = 0;
        List<Integer> confUserIds = new ArrayList<>();
        for(RuleVo ruleVo : list2){
            if(ruleVo.getRuleRange() <= list1.size()){
                for(int i = count;i < ruleVo.getRuleRange();i++){
                    CycleVo vo = copy(cycleVo);
                    vo.setUserName(list1.get(i).getUserName());
                    vo.setRewardMoney(ruleVo.getRuleMoney());
                    vo.setTotalMoney(list1.get(i).getGoodsValue());
                    cycleList.add(vo);
                    confUserIds.add(list1.get(i).getUserId());
                }
                count = ruleVo.getRuleRange();
            }else{
                for(int i = count;i < list1.size();i++){
                    CycleVo vo = copy(cycleVo);
                    vo.setUserName(list1.get(i).getUserName());
                    vo.setRewardMoney(ruleVo.getRuleMoney());
                    vo.setTotalMoney(list1.get(i).getGoodsValue());
                    cycleList.add(vo);
                    confUserIds.add(list1.get(i).getUserId());
                }
                break;
            }
        }
        //没有销售奖励的分销商
        distributorIds.removeAll(confUserIds);
        for(Integer distributorId : distributorIds){
            String userName = vipDao.selectById(distributorId).getUserName();
            CycleVo vo = copy(cycleVo);
            vo.setUserName(userName);
            vo.setRewardMoney(BigDecimal.ZERO);
            vo.setTotalMoney(BigDecimal.ZERO);
            cycleList.add(vo);
        }
        Map<String, Object> map = getMap(param, cycleList);
        return AjaxResult.success(map);
    }

    @Override
    public AjaxResult<?> grant(int cycleId) {
        //查出周期信息
        MPJLambdaWrapper<CycleVo> mpj = new MPJLambdaWrapper<>();
        mpj.selectAll(CycleVo.class)
                .eq(CycleVo::getCycleId, cycleId);
        CycleVo cycleVo = cycleDao.selectOne(mpj);
        //查出奖励指标
        RewardVo rewardVo = rewardDao.selectById(cycleVo.getRewardConfId());
        BigDecimal confBasic = rewardVo.getConfBasic();
        //查出该周期的所有奖励规则
        List<RuleVo> list2 = getRule(Integer.parseInt(cycleVo.getRewardConfId()));
        //查出分销商的销售金额
        List<Nouse> list = rewardDao.sumReward(cycleVo);
        //过滤掉没有达到销售指标的分销商
        List<Nouse> list1 = list.stream().filter(item -> item.getGoodsValue().compareTo(confBasic) >= 0).collect(Collectors.toList());
        int count = 0;
        for(RuleVo ruleVo : list2){
            if(ruleVo.getRuleRange() <= list1.size()){
                for(int i = count;i < ruleVo.getRuleRange();i++){
                    updateAndInsert(ruleVo,list1,i);
                }
                count = ruleVo.getRuleRange();
            }else{
                for(int i = count;i < list1.size();i++){
                    updateAndInsert(ruleVo,list1,i);
                }
                break;
            }
        }
        //修改周期的发放状态和发放时间
        cycleVo.setGrantStatus("1");
        cycleVo.setGrantTime(DateUtil.now());
        cycleDao.updateById(cycleVo);
        return AjaxResult.success();
    }


//    @Scheduled(fixedDelay = 5000)
    @Scheduled(cron = "0 0 0 * * ?")// 每天凌晨12点触发任务
    public void grant2() {
        System.out.println("定时任务--------");
        List<CycleVo> list = cycleDao.selectList(new LambdaQueryWrapper<CycleVo>().eq(CycleVo::getGrantStatus, "0"));
        if(list != null && list.size() > 0){
            for(CycleVo vo : list){
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String now = DateUtil.now();
                String end = vo.getCycleEndTime();
                try {
                    Date start = sdf.parse(now);
                    Date end1 = sdf.parse(end);
                    if(start.after(end1)){
                        grant(vo.getCycleId());
                    }
                }catch (Exception e){
                    System.out.println("时间格式错误");
                }
            }
        }
    }


    public void updateAndInsert(RuleVo ruleVo,List<Nouse> list1,int i){
        BigDecimal rewardMoney = ruleVo.getRuleMoney();
        UserVo vo = vipDao.selectById(list1.get(i).getUserId());
        MoneyVo moneyVo = getMoneyVo(vo,rewardMoney);
        moneyDao.insert(moneyVo);
        UserVo userVo = updateMoney(vo,rewardMoney);
        vipDao.updateById(userVo);
    }

    public MoneyVo getMoneyVo(UserVo userVo,BigDecimal disMoney){
        MoneyVo money = new MoneyVo();
        money.setUserName(userVo.getUserName());
        money.setUserTel(userVo.getUserTel());
        money.setCreateTime(now());
        money.setUserId(String.valueOf(userVo.getUserId()));
        money.setAccountType("余额");
        money.setSiteId(userVo.getSiteId());
        money.setMoneySourceId("销售奖励");
        money.setMoneyChange(disMoney);
        money.setMoneyFinal(userVo.getUserCanuseMoney().add(disMoney));
        money.setMoneyStatus("0");
        return money;
    }

    public UserVo updateMoney(UserVo userVo,BigDecimal disMoney){
        userVo.setUserCantBe(userVo.getUserCantBe().add(disMoney));
        userVo.setUserCanuseMoney(userVo.getUserCanuseMoney().add(disMoney));
        userVo.setUserDistributionMoney(userVo.getUserDistributionMoney().add(disMoney));
        userVo.setUserTotalMoney(userVo.getUserTotalMoney().add(disMoney));
        userVo.setUserTotalDistribution(userVo.getUserTotalDistribution().add(disMoney));
        return userVo;
    }

    public List<RuleVo> getRule(int rewardConfId){
        //查出该周期内所有奖励规则
        List<Integer> ruleIds = rewardRuleDao.selectList(new LambdaQueryWrapper<RewardRuleMiddle>()
                .eq(RewardRuleMiddle::getRewardId, rewardConfId))
                .stream().map(RewardRuleMiddle::getRuleId).collect(Collectors.toList());
        List<RuleVo> list = ruleDao.selectList(new LambdaQueryWrapper<RuleVo>().in(RuleVo::getRuleId, ruleIds).orderByDesc(RuleVo::getRuleMoney));
        return list;
    }

    public CycleVo copy(CycleVo cycleVo1){
        CycleVo cycleVo = new CycleVo();
        cycleVo.setCycleId(cycleVo1.getCycleId());
        cycleVo.setCycleStartTime(cycleVo1.getCycleStartTime());
        cycleVo.setCycleEndTime(cycleVo1.getCycleEndTime());
        cycleVo.setSiteId(cycleVo1.getSiteId());
        cycleVo.setRewardConfId(cycleVo1.getRewardConfId());
        cycleVo.setGrantStatus(cycleVo1.getGrantStatus());
        cycleVo.setSummaryStatus(cycleVo1.getSummaryStatus());
        cycleVo.setSummaryTime(cycleVo1.getSummaryTime());
        cycleVo.setGrantTime(cycleVo1.getGrantTime());
        cycleVo.setRewardType(cycleVo1.getRewardType());
        cycleVo.setRewardMoney(cycleVo1.getRewardMoney());
        return cycleVo;
    }

    public Map<String, Object> getMap(Map<String, Object> param, List<CycleVo> cycleList){
        Map<String, Object> map = new HashMap<>();
        if(param.get("pageIndex") != null && !"".equals(param.get("pageIndex"))){
            System.out.println("111111111111");
            int pageIndex = Integer.parseInt(param.get("pageIndex").toString());
            int pageSize = Integer.parseInt(param.get("pageSize").toString());
            map.put("list", cycleList.subList((pageIndex-1)*pageSize, (pageIndex-1)*pageSize+pageSize));
        }else{
            if(cycleList.size() > 5)
                map.put("list", cycleList.subList(0, 5));
            else
                map.put("list", cycleList);
        }
        Page<DistributorVo> page = getPage2(param);
        List<DistributorVo> no = distributorDao.selectPage(page, null).getRecords();
        map.put("pageCount", page.getPages());
        return map;
    }


    private Page<CycleVo> getPage(Map<String,Object> map){
        if ( map.get("pageIndex") == null || "".equals(map.get("pageIndex")) )
            map.put("pageIndex",1);
        if ( map.get("pageSize") == null || "".equals(map.get("pageSize")) )
            map.put("pageSize",10);
        Long pageIndex = Long.valueOf(map.get("pageIndex").toString());
        Long pageSize = Long.valueOf(map.get("pageSize").toString());
        Page<CycleVo> page = new Page<>(pageIndex,pageSize);
        return page;
    }

    private Page<DistributorVo> getPage2(Map<String,Object> map){
        if ( map.get("pageIndex") == null || "".equals(map.get("pageIndex")) )
            map.put("pageIndex",1);
        if ( map.get("pageSize") == null || "".equals(map.get("pageSize")) )
            map.put("pageSize",10);
        Long pageIndex = Long.valueOf(map.get("pageIndex").toString());
        Long pageSize = Long.valueOf(map.get("pageSize").toString());
        Page<DistributorVo> page = new Page<>(pageIndex,pageSize);
        return page;
    }
}
